import 'dart:math';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:ichinesereader/actflLevelDescription.dart';
import 'package:ichinesereader/constants.dart';
import 'package:ichinesereader/models/evaluation/acflLevelDescriptionResult.dart';
import 'package:ichinesereader/models/evaluation/benchmarkSkillChartData.dart';
import 'package:ichinesereader/models/evaluation/evaluationBenchmarkReportResult.dart';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart';

Future<Uint8List> generatePdf(
    PdfPageFormat pageFormat, BenchmarkReportData reportData, int level) async {
  return await buildPdf(pageFormat, reportData, level);
}

Future<Uint8List> buildPdf(
    PdfPageFormat pageFormat, BenchmarkReportData reportData, int level) async {
  // Create a PDF document.
  final doc = Document();
  final font = await rootBundle.load("assets/fonts/GenYoMinTWM.ttf");
  final theme = ThemeData.withFont(base: Font.ttf(font));
  var data = reportData;
  double? getAverage({int? num1, int? num2, int? num3, int? num4}) {
    var newArray = [num1, num2, num3, num4];
    var sum = 0;
    var no = 0;
    newArray.forEach((element) {
      if (element != null) {
        sum += element;
        no += 1;
      }
    });
    if (no == 0) {
      return null;
    }
    return sum / no;
  }

  double? overallTemp = getAverage(
      num1: data.listening?.summary ?? null,
      num2: data.reading?.summary ?? null,
      num3: data.speaking?.summary ?? null,
      num4: data.writing?.summary ?? null);
  double? overall = overallTemp != null ? overallTemp / 10 : null;
  var targetLevel = Constants.bookLevelColors
          .firstWhereOrNull((element) => element.level == (level + 1))
          ?.actflLevel ??
      '';

  var targetBaseLevel = Constants.bookLevelColors
          .firstWhereOrNull((element) => element.level == (level))
          ?.actflLevel ??
      '';
  final List<SkillPoint> skillPoints = Constants.ReportTypes.map((t) {
    var temp = data.get(t);
    if (temp != null) {
      return new SkillPoint(
          t.toUpperCase(),
          (data.get(t).summary / 10).toDouble(),
          convertToLevel(percentage: data.get(t).summary));
    } else {
      return new SkillPoint(
          t.toUpperCase(), null, convertToLevel(percentage: 0));
    }
  }).toList();

  final List<DetailContent> detailContents = Constants.ReportTypes.map((t) {
    var temp = data.get(t);
    if (temp != null) {
      List<DescriptionData> descriptionList =
          Description.actflLevelDescription.get(targetLevel).get(t);
      List<DescriptionData> strategyList =
          Description.actflLevelStrategy.get(targetLevel).get(t);
      List<DescriptionData> suggestList = Description
          .actflLevelSuggest[convertToIndex(percentage: temp.summary)]
          .get(t);
      return new DetailContent(
          t,
          Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              if (temp.conversationsAndDiscussions != null)
                Text("Conversations and discussions: " +
                    temp.conversationsAndDiscussions.toString() +
                    '%'),
              if (temp.informationalTexts != null)
                Text("Informational texts: " +
                    temp.informationalTexts.toString() +
                    "%"),
              if (data.get(t).fictionalTexts != null)
                Text(
                    "Fictional texts: " + temp.fictionalTexts.toString() + "%"),
              if (data.get(t).interpersonalCommunication != null)
                Text("Interpersonal Communication: " +
                    temp.interpersonalCommunication.toString() +
                    "%"),
              if (temp.presentationalCommunication != null)
                Text("Presentational Communication: " +
                    temp.presentationalCommunication.toString() +
                    "%"),
              Divider(
                  height: 10,
                  thickness: 1,
                  color: PdfColor.fromHex("#dddddddd")),
              Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: strategyList
                      .map((item) => Column(
                              crossAxisAlignment: CrossAxisAlignment.start,
                              children: [
                                Text(item.summary!),
                                Column(
                                    crossAxisAlignment:
                                        CrossAxisAlignment.start,
                                    children: item.contents!
                                        .map((content) => Text("- " + content))
                                        .toList())
                              ]))
                      .toList()),
            ],
          ),
          Column(
              children: descriptionList
                  .map((item) => Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text(item.summary!),
                            ListView.builder(
                              itemCount: item.contents!.length,
                              itemBuilder: (context, index) {
                                final i = item.contents![index];
                                return Wrap(children: [Text("- " + i)]);
                              },
                            ),
                          ]))
                  .toList()),
          Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: suggestList
                  .map((item) => Column(children: [
                        Text(item.summary!),
                      ]))
                  .toList()),
          temp.summary);
    } else {
      return new DetailContent(t, Text("Not tested"), Text(""), Text(""), null);
    }
  }).toList();

  List<BenchmarkSkillChartData> skillChartData = Constants.ReportTypes.map((t) {
    var temp = data.get(t);
    if (temp != null) {
      return new BenchmarkSkillChartData(t, temp.summary);
    } else {
      return new BenchmarkSkillChartData(t, 0);
    }
  }).toList();
  // Add page to the PDF

  Widget _contentOverall(Context context) {
    return Column(children: [
      Row(
        children: [
          Text("School/Class:".tr),
          SizedBox(width: 10),
          Text(data.schoolName!)
        ],
      ),
      SizedBox(height: 10),
      Row(
        children: [
          Text("Student:".tr),
          SizedBox(width: 10),
          Text(data.studentName!)
        ],
      ),
      SizedBox(height: 10),
      Row(
        children: [
          Text("Target Test Level:".tr),
          SizedBox(width: 10),
          Text('$targetBaseLevel -> $targetLevel')
        ],
      ),
      SizedBox(height: 10),
      Row(
        children: [
          Text(data.studentName! + "'s Overall Chinese Performance:".tr),
          Text(overall != null
              ? convertToLevel(percentage: overall.toInt())
              : 'Not tested')
        ],
      )
    ]);
  }

  Widget _contentTable(Context context) {
    List<String> tableHeaders = [
      'Overall',
      overall != null ? overall.toString() : 'Not tested',
      overall != null
          ? convertToLevel(percentage: overall.toInt())
          : 'Not tested',
    ];
    return Table.fromTextArray(
      border: null,
      cellAlignment: Alignment.centerLeft,
      // headerDecoration: BoxDecoration(
      //   borderRadius: const BorderRadius.all(Radius.circular(2)),
      //   color: baseColor,
      // ),
      headerHeight: 25,
      cellHeight: 40,
      cellAlignments: {
        0: Alignment.center,
        1: Alignment.center,
        2: Alignment.center,
      },
      headerStyle: TextStyle(
        fontSize: 15,
        fontWeight: FontWeight.bold,
      ),
      rowDecoration: BoxDecoration(
        border: Border(
          bottom: BorderSide(
            width: .5,
          ),
        ),
      ),
      headers: List<String>.generate(
        tableHeaders.length,
        (col) => tableHeaders[col],
      ),
      data: List<List<String>>.generate(
        skillPoints.length,
        (row) => List<String>.generate(
          tableHeaders.length,
          (col) => skillPoints[row].getIndex(col),
        ),
      ),
    );
  }

  // Widget _contentTableDetailRow(Context context, int index) {
  //   var tableHeaders = [
  //     detailContents[index].getIndex(4),
  //     detailContents[index].getIndex(3),
  //   ];

  //   return Table(
  //       border: TableBorder.all(),
  //       columnWidths: const <int, TableColumnWidth>{
  //         0: IntrinsicColumnWidth(),
  //         1: FlexColumnWidth(),
  //       },
  //       defaultVerticalAlignment: TableCellVerticalAlignment.middle,
  //       children: [
  //         TableRow(children: tableHeaders),
  //         TableRow(children: [
  //           Container(
  //               child: Text(
  //                 'Overall / Strategies',
  //               ),
  //               padding: EdgeInsets.all(10)),
  //           detailContents[index].getIndex(0),
  //         ]),
  //         TableRow(children: [
  //           Container(
  //               child: Text('Level Description'), padding: EdgeInsets.all(10)),
  //           detailContents[index].getIndex(1),
  //         ]),
  //         TableRow(children: [
  //           Container(child: Text('Suggest'), padding: EdgeInsets.all(10)),
  //           detailContents[index].getIndex(2),
  //         ])
  //       ]);
  // }

  Widget _contentTableDetail(Context context, int index) {
    var tableHeaders = [
      Container(
          child: Column(children: [
        detailContents[index].getIndex(4),
        detailContents[index].getIndex(3),
      ])),
      Container(child: Text('Level Description'), padding: EdgeInsets.all(10)),
      Container(child: Text('Suggest'), padding: EdgeInsets.all(10)),
    ];

    return Table(
        border: TableBorder.all(),
        columnWidths: const <int, TableColumnWidth>{
          0: FlexColumnWidth(),
          1: FractionColumnWidth(0.4),
          2: FlexColumnWidth(),
        },
        defaultVerticalAlignment: TableCellVerticalAlignment.middle,
        children: [
          TableRow(children: tableHeaders),
          TableRow(children: [
            detailContents[index].getIndex(0),
            detailContents[index].getIndex(1),
            detailContents[index].getIndex(2),
          ]),
        ]);
  }

  final chart1 = Chart(
    left: Container(
      alignment: Alignment.topCenter,
      margin: const EdgeInsets.only(right: 5, top: 10),
      child: Transform.rotateBox(
        angle: pi / 2,
        child: Text('Point'),
      ),
    ),
    overlay: ChartLegend(
      position: const Alignment(-.7, 1),
      decoration: BoxDecoration(
        color: PdfColors.white,
        border: Border.all(
          color: PdfColors.black,
          width: .5,
        ),
      ),
    ),
    grid: CartesianGrid(
      xAxis: FixedAxis.fromStrings(
        List<String>.generate(
            skillChartData.length, (index) => skillChartData[index].item),
        marginStart: 30,
        marginEnd: 30,
        ticks: true,
      ),
      yAxis: FixedAxis(
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
        format: (v) => '$v',
        divisions: true,
      ),
    ),
    datasets: [
      BarDataSet(
        color: PdfColors.blue100,
        legend: "Skills",
        width: 15,
        offset: -10,
        //  borderColor: baseColor,
        data: List<PointChartValue>.generate(
          skillChartData.length,
          (i) {
            final v = skillChartData[i].summary as num;
            return PointChartValue(i.toDouble(), v / 10.toDouble());
          },
        ),
      ),
    ],
  );

  doc.addPage(Page(
    theme: theme,
    build: (context) => Column(children: [
      _contentOverall(context),
      SizedBox(height: 70),
      _contentTable(context),
      SizedBox(height: 70),
      Container(child: chart1, height: 250)
      //     Expanded(flex: 3, child: chart1),
    ]),
  ));

  if (detailContents[0].summary != null) {
    doc.addPage(Page(
        theme: theme,
        build: (context) => Column(
              children: [
                _contentTableDetail(context, 0),
                SizedBox(height: 10),
                if (data.get(detailContents[0].type.toLowerCase())?.comment !=
                    null)
                  Text("Comment : " +
                      data.get(detailContents[0].type.toLowerCase())?.comment),
                SizedBox(height: 20)
              ],
            )));
  }
  if (detailContents[1].summary != null) {
    doc.addPage(Page(
        theme: theme,
        build: (context) => Column(
              children: [
                _contentTableDetail(context, 1),
                SizedBox(height: 10),
                if (data.get(detailContents[1].type.toLowerCase())?.comment !=
                    null)
                  Text("Comment : " +
                      data.get(detailContents[1].type.toLowerCase())?.comment),
                SizedBox(height: 20)
              ],
            )));
  }
  if (detailContents[2].summary != null) {
    doc.addPage(Page(
        theme: theme,
        build: (context) => Column(
              children: [
                _contentTableDetail(context, 2),
                SizedBox(height: 10),
                if (data.get(detailContents[2].type.toLowerCase())?.comment !=
                    null)
                  Text("Comment : " +
                      data.get(detailContents[2].type.toLowerCase())?.comment),
                SizedBox(height: 20)
              ],
            )));
  }
  if (detailContents[3].summary != null) {
    doc.addPage(Page(
        theme: theme,
        build: (context) => Column(
              children: [
                _contentTableDetail(context, 3),
                SizedBox(height: 10),
                if (data.get(detailContents[3].type.toLowerCase())?.comment !=
                    null)
                  Text("Comment : " +
                      data.get(detailContents[3].type.toLowerCase())?.comment),
                SizedBox(height: 20)
              ],
            )));
  }
  return doc.save();
}

String convertToLevel({int? percentage = 0}) {
  return Constants.TargetLevel[convertToIndex(percentage: percentage)];
}

int convertToIndex({int? percentage = 0}) {
  if (percentage == null) {
    return 0;
  }
  if (percentage > 90) {
    return 2;
  } else if (percentage < 60) {
    return 0;
  } else {
    return 1;
  }
}

class SkillPoint {
  SkillPoint(
    this.type,
    this.point,
    this.performance,
  );

  final String type;
  double? point;
  final String performance;

  String getIndex(int index) {
    switch (index) {
      case 0:
        return type;
      case 1:
        return point != null ? point.toString() : "Not tested";
      case 2:
        return point != null
            ? convertToLevel(percentage: point?.toInt() ?? 0)
            : "Not tested";
    }
    return '';
  }
}

class DetailContent {
  DetailContent(
    this.type,
    this.points,
    this.description,
    this.suggest,
    this.summary,
  );

  final Widget points;
  final Widget description;
  final Widget suggest;
  final String type;
  int? summary;

  Widget getIndex(int index) {
    switch (index) {
      case 0:
        return Container(child: points, padding: EdgeInsets.all(5));
      case 1:
        return Container(child: description, padding: EdgeInsets.all(5));
      case 2:
        return Container(child: suggest, padding: EdgeInsets.all(5));
      case 3:
        return Text(convertToLevel(percentage: summary));
      case 4:
        return Text(type.toUpperCase());
    }
    return Text('');
  }

  Map<String, dynamic> toMap() {
    return {
      "points": points,
      "description": description,
      "suggest": suggest,
      "type": type
    };
  }
}
